// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
//===------- RLLVMCompiler.cpp - The Reactor just in time compiler ---------===//
//
//                            The VMKit project
//
// This file is distributed under the Purdue University Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>

#include <llvm/ADT/OwningPtr.h>

#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/system_error.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/IRBuilder.h>

#include <llvm/Bitcode/ReaderWriter.h>

#include <llvm/Analysis/DIBuilder.h>
#include <llvm/Target/TargetData.h>

#include "util.h"
#include "Reactor.h"
#include "RCompiler.h"
#include "RModule.h"
#include "Closure.h"

using namespace R;
using namespace llvm;

RCompiler::RCompiler() : RCompilerCommon(loadSelfModule()) {
  debugFactory = new DIBuilder(*selfModule);
  RIntrinsics.init(selfModule);
}

RCompiler::~RCompiler() {
  delete debugFactory;
}

llvm::Module* RCompiler::loadSelfModule() {
	llvm::InitializeNativeTarget();

	llvm::OwningPtr<llvm::MemoryBuffer> buf;
	llvm::error_code err;
	if((err = llvm::MemoryBuffer::getFile(reactor_module_path, buf))) {
		warning("unable to open my own bitcode %s", err.message().c_str());
	}

	return llvm::ParseBitcodeFile(buf.take(), llvm::getGlobalContext());
}

void RCompiler::generateCode(llvm::Function* func) {
	uint64_t moduleId, funcNo;
	sscanf(func->getName().data(), "r-func-"WORD"-"WORD, &moduleId, &funcNo);
	RModule* module = vm->lookupModule(moduleId);

	rerror_on(!module, "unable to find module "WORD, moduleId);
	module->generateCode(func, funcNo);
}

llvm::Function* RCompiler::llvmFunction(RModule* module, uint64_t funcNo) {
	int  pc = module->funInfos[funcNo].start;
	char name[256];
	sprintf(name, "r-func-"WORD"-"WORD, module->moduleId, funcNo);
	llvm::Function* func = Function::Create(RIntrinsics.rfunctionType, GlobalValue::ExternalLinkage, name, selfModule);

	func->setGC("vmkit");
//	func->addFnAttr(Attribute::NoInline);
//	func->addFnAttr(Attribute::NoUnwind);
	return func;
}
